{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1 一阶微分边缘算子\n",
    "## 1.1 Roberts Cross算子\n",
    "Roberts Cross算子是一个简单、快速的算子，其能够识别图像的高频部分（常常对应于图像的边缘）。采用Roberts算子进行边缘检测的原理是：用图像像素之间的一阶离散差分来近似梯度值，利用局部一阶差分算子来进行边缘检测。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "# 读取图片\n",
    "img = cv2.imread('../images/lena.png', 0)\n",
    "rows, cols = img.shape\n",
    "img_con = np.zeros([rows, cols])\n",
    "img_edge = np.zeros([rows, cols])\n",
    "\n",
    "kernel_x = np.array([[1, 0],[0, -1]], dtype = int)\n",
    "kernel_y = np.array([[0, -1],[1, 0]], dtype = int)\n",
    "\n",
    "x = cv2.filter2D(img, -1, kernel_x)\n",
    "y = cv2.filter2D(img, -1, kernel_y)\n",
    "\n",
    "# 线性加权\n",
    "img_con = cv2.addWeighted(cv2.convertScaleAbs(x), 0.5, cv2.convertScaleAbs(y), 0.5, 0)\n",
    "\n",
    "H = 20\n",
    "for row in range(rows):\n",
    "    for col in range(cols):\n",
    "        if img_con[row, col] >= H:\n",
    "            img_edge[row, col] = img_con[row, col]\n",
    "\n",
    "# 绘制\n",
    "cv2.imshow('original', img)\n",
    "cv2.imshow('Roberts Cross', img_con)\n",
    "cv2.imshow('Image edges', img_edge)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.2 Prewitt算子\n",
    "Prewitt算子将差分运算与局部平均相结合，在3×3邻域内计算梯度，虽然可以抑制噪声，但是同时也在一定程度上模糊了图像的边缘信息，无法精确定位边缘位置。Prewitt算子采用一组方向卷积核遍历图像，从水平和垂直两个方向进行边缘检测，上下左右算子相同，去掉伪边缘，对噪声具有平滑作用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "# 读取图片\n",
    "img = cv2.imread('../images/lena.png', 0)\n",
    "rows, cols = img.shape\n",
    "img_con = np.zeros([rows, cols])\n",
    "img_edge = np.zeros([rows, cols])\n",
    "\n",
    "kernel_x = np.array([[-1, 0, 1],[-1, 0, 1],[-1, 0, 1]], dtype = int)\n",
    "kernel_y = np.array([[-1, -1, -1],[0, 0, 0], [1, 1, 1]], dtype = int)\n",
    "\n",
    "x = cv2.filter2D(img, -1, kernel_x)\n",
    "y = cv2.filter2D(img, -1, kernel_y)\n",
    "\n",
    "# 线性加权\n",
    "img_con = cv2.addWeighted(cv2.convertScaleAbs(x), 0.5, cv2.convertScaleAbs(y), 0.5, 0)\n",
    "\n",
    "H = 20\n",
    "for row in range(rows):\n",
    "    for col in range(cols):\n",
    "        if img_con[row, col] >= H:\n",
    "            img_edge[row, col] = img_con[row, col]\n",
    "\n",
    "# 绘图\n",
    "cv2.imshow('original', img)\n",
    "cv2.imshow('Prewitt', img_con)\n",
    "cv2.imshow('Image edges', img_edge)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()\t"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.3 Sobel算子\n",
    "Sobel算子是对相邻像素点间的像素做加权差分处理（这点与Roberts Cross和Prewitt均不同），然后用于检测图像边缘信息。Sobel算子在Prewitt算子的基础上做了细微变化，即在中心系数上使用了更大的权重，以提供更好的图像平滑。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "# 读取图片\n",
    "img = cv2.imread('../images/lena.png', 0)\n",
    "rows, cols = img.shape\n",
    "img_con = np.zeros([rows, cols])\n",
    "img_edge = np.zeros([rows, cols])\n",
    "kernel_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]], dtype = int)\n",
    "kernel_y = np.array([[1, 2, 1],[0, 0, 0], [-1, -2, -1]], dtype = int)\n",
    "x = cv2.filter2D(img, -1, kernel_x)\n",
    "y = cv2.filter2D(img, -1, kernel_y)\n",
    "# 线性加权\n",
    "img_con = cv2.addWeighted(cv2.convertScaleAbs(x), 0.5, cv2.convertScaleAbs(y), 0.5, 0)\n",
    "H = 20\n",
    "for row in range(rows):\n",
    "    for col in range(cols):\n",
    "        if img_con[row, col] >= H:\n",
    "            img_edge[row, col] = img_con[row, col]\n",
    "# 绘制\n",
    "cv2.imshow('original', img)\n",
    "cv2.imshow('Sobel', img_con)\n",
    "cv2.imshow('Image edges', img_edge)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2 二阶微分边缘算子\n",
    "## 2.1 LoG算子\n",
    "Laplacian算子采用二阶微分处理图像，其对图片中的噪声很敏感，为了解决这一问题，在进行使用Laplacian算子之前经常先对图像进行高斯平滑滤波处理，以降低图片中的高频噪声影响。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "original_img = cv2.imread('../images/lena.png', 0)\n",
    "blured_img = cv2.GaussianBlur(original_img, (3, 3), 0)\n",
    "laplacian = cv2.Laplacian(blured_img, cv2.CV_16S, ksize=3)\n",
    "dest = laplacian/laplacian.max()\n",
    "\n",
    "# 绘制\n",
    "cv2.imshow('Original', original_img)\n",
    "cv2.imshow('Blured image', blured_img)\n",
    "cv2.imshow('Image edges', dest)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3 最优算子\n",
    "## 3.1 Canny算子\n",
    "Canny算子的基本思路是先使用二维高斯滤波卷积核对图像进行平滑处理，然后利用微分算子分别求出像素值的x、y方向梯度（幅值与方向），然后进行非极大值抑制，找出像素在梯度方向上的最大值以确定是否将中心像素点暂定为边缘点，最后进行双阈值选择，对求出的暂定边缘点进行最后的判断，确定最终边缘。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "# read the image in grey mode\n",
    "original_img = cv2.imread('../images/lena.png', 0)\n",
    "img1 = cv2.GaussianBlur(original_img, (3,3), 0)\n",
    "\n",
    "canny = cv2.Canny(img1, 50, 150)\n",
    "cv2.imshow('original', original_img)\n",
    "cv2.imshow('Canny 1', canny)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
